/**
* This file is part of mobileworks.
*
* mobileworks is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* You should have received a copy of the GNU General Public License
* along with dev.clipall.  If not, see <http://www.gnu.org/licenses/>.
*
* https://code.google.com/p/mobileworks/
*/

package gml;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 *
 * @author Erol Hira
 */
public class Fsm {
    
    private ArrayList<ArrayList<Integer>> props = new ArrayList<ArrayList<Integer>>();
    private ArrayList<ArrayList<Integer>> commands = new ArrayList<ArrayList<Integer>>();
    private ArrayList<ArrayList<Integer>> transitions = new ArrayList<ArrayList<Integer>>();
    private ArrayList<ArrayList<Integer>> actions = new ArrayList<ArrayList<Integer>>();    
    private ArrayList<ArrayList<String>> functions = new ArrayList<ArrayList<String>>();
    private ArrayList<String> nonNumericPropValues = new ArrayList<String>();
    private int[][] propArr;    
    private int[][] commandArr;
    private int[][] transArr;
    private int[][] actionArr;
    private String[][] funcArr;    
    private String[] nonNumericPropValuesArr;
            
    
    private HashMap<String, Integer> styleIdMap = new HashMap<String, Integer>();
    private HashMap<String, Integer> pageIdMap = new HashMap<String, Integer>();
    private HashMap<String, Integer> stateIdMap = new HashMap<String, Integer>();    
    private HashMap<String, Integer> commandMap = new HashMap<String, Integer>();
    private HashMap<String, Integer> transitionMap = new HashMap<String, Integer>();
    private HashMap<String, Integer> actionMap = new HashMap<String, Integer>();
    
    private HashMap<String, Integer> propMap = new HashMap<String, Integer>();
    private HashMap<String, Integer> componentIdMap = new HashMap<String, Integer>();
    
    
    private int[][][][] pages;
    
    private int[][][] states;
    
    private int[][] styles;
    
    private ArrayList<String> strings = new ArrayList<String>();
    
    public Fsm(){
        initPropertyMap();
        initComponentIdMap();
    }
    
    public int addFunction(ArrayList<String> func){
        functions.add(func);
        return functions.size() - 1;
    }
    
    public void addToStyleIdMap(String id, int index){
        if(styleIdMap.containsKey(id)){
            Logger.getLogger(Fsm.class.getName()).log(Level.WARNING, "map already contains the id " + id);
        }
        styleIdMap.put(id, index);
    }
    
    public void addToPageIdMap(String id, int index){
        if(pageIdMap.containsKey(id)){
            Logger.getLogger(Fsm.class.getName()).log(Level.WARNING, "map already contains the id " + id);
        }
        pageIdMap.put(id, index);
    }
    
    public void addToStateIdMap(String id, int index){        
        if(stateIdMap.containsKey(id)){
            Logger.getLogger(Fsm.class.getName()).log(Level.WARNING, "map already contains the id " + id);
        }
        stateIdMap.put(id, index);
    }
    
    public int makeString(String string){
        
        if(strings.contains(string)){
            return strings.indexOf(string);
        } else {
            strings.add(string);
            return strings.size() - 1;
        }
    }
    
    public int getPageIdIndex(String id){
        return pageIdMap.get(id);
    }
    
    public int getStyleIdIndex(String id){
        return styleIdMap.get(id);
    }
    
    public int getStateIdIndex(String id){
        return stateIdMap.get(id);
    }
    
    public int getActionId(String actionId){        
        return actionMap.get(actionId);
    } 
    
    public int addActionId(String actionId){
        
        if(actionMap.containsKey(actionId) == false){
            actionMap.put(actionId, actionMap.keySet().size());
        } 
        
        return actionMap.get(actionId);
    }
    
    // !!!!! equality check is not needed and may cause conflictions !!! : no just, it's just unneeded
    public int addAction(ArrayList<Integer> action){
     
        int cnt = 0;
        for(ArrayList<Integer> p : actions){
                        
            if(p.get(0).equals(action.get(0)) 
                    && 
                    p.get(1).equals(action.get(1))){
                return cnt;
            }
            
            cnt ++;
        }
        
        actions.add(action);                
        
        return cnt;
    }
    
    public int getTransitionId(String transitionId){        
        return transitionMap.get(transitionId);
    } 
    
    public int addTransitionId(String transitionId){
        
        if(transitionMap.containsKey(transitionId) == false){
            transitionMap.put(transitionId, transitionMap.keySet().size());
        } 
        
        return transitionMap.get(transitionId);
    }
    
    public int addTransition(ArrayList<Integer> transition){
     
        int cnt = 0;
        for(ArrayList<Integer> p : transitions){
                        
            if(p.get(0).equals(transition.get(0)) 
                    && 
                    p.get(1).equals(transition.get(1))){
                return cnt;
            }
            
            cnt ++;
        }
        
        transitions.add(transition);                
        
        return cnt;
    }
    
    public int getCommandId(String commandId){        
        return commandMap.get(commandId);
    }            
    
    public int addCommandId(String commandId){
        
        if(commandMap.containsKey(commandId) == false){
            commandMap.put(commandId, commandMap.keySet().size());
        } 
        
        return commandMap.get(commandId);
    }
    
    public int addCommand(ArrayList<Integer> command){
     
        int cnt = 0;
        for(ArrayList<Integer> p : commands){
                        
            if(p.get(0).equals(command.get(0)) 
                    && 
                    p.get(1).equals(command.get(1))){
                return cnt;
            }
            
            cnt ++;
        }
        
        commands.add(command);                
        
        return cnt;
    }
    
    public int getPropertyId(String prop){        
        return propMap.get(prop);
    }        
    
    public int addProperty(ArrayList<Integer> prop){
        
        int cnt = 0;
        for(ArrayList<Integer> p : props){
                        
            if(p.get(0).equals(prop.get(0)) 
                    && 
                    p.get(1).equals(prop.get(1))){
                return cnt;
            }
            
            cnt ++;
        }
        
        props.add(prop);
        
        return cnt;
    }
    
    public void setArrays(){
        
        propArr = new int[props.size()][];
        int index = 0;
        for(ArrayList<Integer> array : props){
            
            propArr[index] = new int[array.size()];
            
            int i = 0;
            for(int k : array){
                
                propArr[index][i] = k;
                
                i ++;
            }
            
            index ++;
        }
        
        //
        
        commandArr = new int[commands.size()][];
        index = 0;
        for(ArrayList<Integer> array : commands){
            
            commandArr[index] = new int[array.size()];
            
            int i = 0;
            for(int k : array){
                
                commandArr[index][i] = k;
                
                i ++;
            }
            
            index ++;
        }
        
        //
        
        transArr = new int[transitions.size()][];
        index = 0;
        for(ArrayList<Integer> array : transitions){
            
            transArr[index] = new int[array.size()];
            
            int i = 0;
            for(int k : array){
                
                transArr[index][i] = k;
                
                i ++;
            }
            
            index ++;
        }
        
        //
        
        actionArr = new int[actions.size()][];
        index = 0;
        for(ArrayList<Integer> array : actions){
            
            actionArr[index] = new int[array.size()];
            
            int i = 0;
            for(int k : array){
                
                actionArr[index][i] = k;
                
                i ++;
            }
            
            index ++;
        }
        
        //
        
        funcArr = new String[functions.size()][];
        index = 0;
        for(ArrayList<String> array : functions){
            
            funcArr[index] = new String[array.size()];
            
            int i = 0;
            for(String k : array){
                
                funcArr[index][i] = k;
                
                i ++;
            }
            
            index ++;
        }
        
        //
        
        nonNumericPropValuesArr = new String[nonNumericPropValues.size()];
        index = 0;
        for(String val : nonNumericPropValues){
            
            nonNumericPropValuesArr[index] = nonNumericPropValues.get(index);
            
            index ++;
        }
    }

    public void addPropValue(ArrayList<Integer> p, String name, String value) {
        
        if(name.equals("x") ||
                name.equals("y") ||
                name.equals("width") ||
                name.equals("height") ||
                name.equals("marginLeft") ||
                name.equals("marginRight") ||
                name.equals("marginTop") ||
                name.equals("marginBottom") ||
                name.equals("outerMarginLeft") ||
                name.equals("outerMarginRight") ||
                name.equals("outerMarginTop") ||
                name.equals("outerMarginBottom") ||
                name.equals("alignment") ||
                name.equals("containerHorizontalAlignment") ||
                name.equals("bgColor") ||
                name.equals("fgColor") ||
                name.equals("zOrder") ||
                name.equals("lineColor") ||
                name.equals("type") ||
                name.equals("frameLineTickness") ||
                name.equals("frameLineColor") ||
                name.equals("selectedBgColor") ||
                name.equals("marginSelectedElementVertical") ||
                name.equals("marginSelectedElementHorizontal") ||
                name.equals("spaceBetweenElements") ||
                name.equals("lineHeight") ||
                name.equals("minDistBetweenIconAndText") ||
                name.equals("maxCountOfElementsInCurrentPage") ||
                name.equals("oll") ||
                name.equals("olt") ||
                name.equals("olc") ||
                name.equals("ill") ||
                name.equals("ilc") ||
                name.equals("ot") ||
                name.equals("oc") ||
                name.equals("position") ||
                name.equals("softButtonType") ||
                name.equals("softButtonHeight") ||
                name.equals("softLineColor") ||
                name.equals("hardLineColor") ||
                name.equals("maxLength")) {
            
            p.add(Integer.parseInt(value));
            
        } else if(name.equals("font") ||
                name.equals("bgImage") ||
                name.equals("elementBgImage") ||
                name.equals("elementSelectedImage") ||
                name.equals("label") ||
                name.equals("data") ||
                name.equals("lineIcon") ||
                name.equals("selectedLineIcon")){
            
            nonNumericPropValues.add(name);
            p.add(nonNumericPropValues.size() - 1);
            
        } else if(name.equals("visible") ||
                name.equals("paintFlag") ||
                name.equals("frameLineVisible") ||
                name.equals("fullscreen") ||
                name.equals("active") ||
                name.equals("outerLineExists") ||
                name.equals("visibleLine")){
            
            int val = value.equals("true") ? 1 : 0;
            p.add(val);
            
        } else if(name.equals("componentType")){
            
            p.add();
        }
    }
    
    public boolean isStringProperty(String prop){
        
        return prop.equals("font") || 
                prop.equals("label") ||
                prop.equals("data") ||
                prop.equals("bgImage");
    }
    
    private void initPropertyMap(){
        
        propMap.put("x", 0);
        propMap.put("y", 1);
        propMap.put("width", 2);
        propMap.put("height", 3);
        propMap.put("marginLeft", 4);
        propMap.put("marginRight", 5);
        propMap.put("marginTop", 6);
        propMap.put("marginBottom", 7);
        propMap.put("outerMarginLeft", 8);
        propMap.put("outerMarginRight", 9);
        propMap.put("outerMarginTop", 10);
        propMap.put("outerMarginBottom", 11);
        propMap.put("alignment", 12);
        propMap.put("containerHorizontalAlignment", 13);
        propMap.put("bgColor", 14);
        propMap.put("fgColor", 15);
        propMap.put("font", 16);
        propMap.put("border", 17); //do not use border, use component 
        propMap.put("bgImage", 18);
        propMap.put("paintFlag", 19);
        propMap.put("visible", 20);
        propMap.put("zOrder", 21);
        propMap.put("label", 22);
        propMap.put("lineColor", 23);
        propMap.put("type", 24);
        propMap.put("data", 25);
        propMap.put("fullscreen", 26);
        propMap.put("frameLineVisible", 27);
        propMap.put("frameLineTickness", 28);
        propMap.put("frameLineColor", 29);
        propMap.put("elementBgImage", 30);
        propMap.put("elementSelectedImage", 31);
        propMap.put("selectedBgColor", 32);
        propMap.put("marginSelectedElementVertical", 33);
        propMap.put("marginSelectedElementHorizontal", 34);
        propMap.put("spaceBetweenElements", 35);
        propMap.put("lineIcon", 36);
        propMap.put("selectedLineIcon", 37);
        propMap.put("lineHeight", 38);
        propMap.put("minDistBetweenIconAndText", 39);
        propMap.put("maxCountOfElementsInCurrentPage", 40);
        propMap.put("oll", 41);
        propMap.put("olt", 42);
        propMap.put("olc", 43);
        propMap.put("ill", 44);
        propMap.put("ilc", 45);
        propMap.put("outerLineExists", 46);
        propMap.put("ot", 47);
        propMap.put("oc", 48);
        propMap.put("defaultCommand", 49);
        propMap.put("commands", 50);
        propMap.put("position", 51);
        propMap.put("softButtonType", 52);
        propMap.put("softButtonHeight", 53);
        propMap.put("active", 54);
        propMap.put("softMenu", 55);
        propMap.put("visibleLine", 56);
        propMap.put("softLineColor", 57);
        propMap.put("hardLineColor", 58);
        propMap.put("maxLength", 59);
        propMap.put("componentType", 60);
        
    }

    private void initComponentIdMap(){
        
        componentIdMap.put("label", 0);
        componentIdMap.put("combobox", 1);
        componentIdMap.put("list", 2);
        componentIdMap.put("textfield", 3);
    }
    
    public int[][] getStyles() {
        return styles;
    }

    public void setStyles(int[][] styles) {
        this.styles = styles;
    }

    public int[][][][] getPages() {
        return pages;
    }

    public void setPages(int[][][][] pages) {
        this.pages = pages;
    }

    public int[][][] getStates() {
        return states;
    }

    public void setStates(int[][][] states) {
        this.states = states;
    }

    public int[][] getPropArr() {
        return propArr;
    }

    public int[][] getCommandArr() {
        return commandArr;
    }

    public int[][] getTransArr() {
        return transArr;
    }

    public int[][] getActionArr() {
        return actionArr;
    }

    public String[][] getFuncArr() {
        return funcArr;
    }

    public String[] getNonNumericPropValuesArr() {
        return nonNumericPropValuesArr;
    }
}
